/*! ******************************************************************************
 *
 * Pentaho
 *
 * Copyright (C) 2024 by Hitachi Vantara, LLC : http://www.pentaho.com
 *
 * Use of this software is governed by the Business Source License included
 * in the LICENSE.TXT file.
 *
 * Change Date: 2029-07-20
 ******************************************************************************/

package org.pentaho.requirejs.impl.plugins;

import org.pentaho.requirejs.IRequireJsPackageConfiguration;
import org.pentaho.requirejs.IRequireJsPackageConfigurationPlugin;
import org.pentaho.requirejs.impl.types.MetaInfRequireJson;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * For packages marked as non-AMD (only possible coming from a META-INF/js/require.json file generated by
 * the pentaho-webjars-deployer), creates a generic shim configuration with both the
 * {@link MetaInfRequireJson#getExports} value (if any) and dependencies that also aren't AMD packages.
 */
public class NomAmdPackageShim implements IRequireJsPackageConfigurationPlugin {
  @Override
  public void apply( IRequireJsPackageConfiguration requireJsPackageConfig,
                     Function<String, IRequireJsPackageConfiguration> dependencyResolver,
                     Function<String, String> resolveModuleId,
                     Map<String, ?> requireConfig ) {
    if ( requireJsPackageConfig.getRequireJsPackage() instanceof MetaInfRequireJson ) {
      MetaInfRequireJson metaInfRequireJson = (MetaInfRequireJson) requireJsPackageConfig.getRequireJsPackage();

      if ( !metaInfRequireJson.isAmdPackage() ) {
        Set<String> packageShimDependencies = new LinkedHashSet<>();

        Map<String, String> dependencies = requireJsPackageConfig.getDependencies();
        for ( String dependencyPackageName : dependencies.keySet() ) {
          final IRequireJsPackageConfiguration dependencyResolvedVersion = dependencyResolver.apply( dependencyPackageName );

          if ( dependencyResolvedVersion != null && dependencyResolvedVersion.getRequireJsPackage() instanceof MetaInfRequireJson ) {
            MetaInfRequireJson depMetaInfRequireJson = (MetaInfRequireJson) dependencyResolvedVersion.getRequireJsPackage();

            if ( !depMetaInfRequireJson.isAmdPackage() ) {
              packageShimDependencies.addAll( dependencyResolvedVersion.getBaseModuleIdsMapping().values() );
            }
          }
        }

        Map<String, Map<String, ?>> shim = (Map<String, Map<String, ?>>) requireConfig.get( "shim" );

        Map<String, Object> packageShim = new HashMap<>();

        if ( !packageShimDependencies.isEmpty() ) {
          packageShim.put( "deps", Collections.unmodifiableList( new ArrayList<>( packageShimDependencies ) ) );
        }

        if ( metaInfRequireJson.getExports() != null && !metaInfRequireJson.getExports().isEmpty() ) {
          packageShim.put( "exports", metaInfRequireJson.getExports() );
        }

        if ( !packageShim.isEmpty() ) {
          Map<String, String> modules = metaInfRequireJson.getModules();
          if ( modules != null ) {
            modules.forEach( ( moduleId, path ) -> {
              String versionedModuleId = resolveModuleId.apply( moduleId );

              shim.put( versionedModuleId, packageShim );

              String moduleMainFile = metaInfRequireJson.getModuleMainFile( moduleId );
              if ( moduleMainFile != null ) {
                shim.put( versionedModuleId + "/" + moduleMainFile, packageShim );
              }
            } );
          }
        }
      }
    }
  }
}
